\chapter{GLib动态类型系统}
由Glib类型系统操作的一个类型，比传统上所讲的Object类型更具一般化。下面查看类型系统中有关类结构和注册新类型的函数，是会对此最好的解释。

\begin{verbatim}
typedef struct _GTypeInfo               GTypeInfo;
struct _GTypeInfo
{
  /* interface types, classed types, instantiated types */
  guint16                class_size;

  GBaseInitFunc          base_init;
  GBaseFinalizeFunc      base_finalize;

  /* classed types, instantiated types */
  GClassInitFunc         class_init;
  GClassFinalizeFunc     class_finalize;
  gconstpointer          class_data;

  /* instantiated types */
  guint16                instance_size;
  guint16                n_preallocs;
  GInstanceInitFunc      instance_init;

  /* value handling */
  const GTypeValueTable *value_table;
};
GType g_type_register_static (GType             parent_type,
                              const gchar      *type_name,
                              const GTypeInfo  *info,
                              GTypeFlags        flags);
GType g_type_register_fundamental (GType                       type_id,
                                   const gchar                *type_name,
                                   const GTypeInfo            *info,
                                   const GTypeFundamentalInfo *finfo,
                                   GTypeFlags                  flags);
\end{verbatim}
\verb|g_type_register_static|和\verb|g_type_register_fundamental|这两个C函数定义在gtype.h中，并在gtype.c中具体实现。
你可以用来在程序的类型系统中注册一个新的GType。一般情况下你永远也不需要使用\verb|g_type_register_fundamental|（除非你是Tim Janik才会这样做），但是这次你要做，在最后一章会向你解释如何创建一个基本类型。

基本类型是不需要从任何其他类型取得的最顶级的类型， 相对的，其他非基本类型是继承于其他类型的。
在由\verb|g_type_init|初始化时，类型系统不仅仅初始化它的内部数据结构，同时也注册一些核心类型：其中一些是基本类型，其他则是从基本类型继承的。

不论是基本还是非基本类型，均由下面的定义步骤：
\begin{itemize}
	\item 类的大小：GTypeInfo的\verb|class_size|。
	\item 类的初始化函数（C++ 构造函数）：GTypeInfo的\verb|base_init|和\verb|class_init|。
	\item 类的销毁函数（C++析构函数）：GTypeInfo的\verb|base_finalize|和\verb|class_finalize|。
	\item 实例的大小（C++参数new）：GTypeInfo中的\verb|instance_size|。
	\item 实例化策略（C++ 类的new operator）：GTypeInfo的\verb|n_preallocs|。
	\item 复制函数（C++的复制操作）：GTypeInfo的\verb|value_table|。
	\item 类的字符标志：GTypeFlags。
\end{itemize}
基本类型同样可以由GTypeFundamentalFlags来定义，并保存在GTypeFundamentallInfo中。非基本类型一般传递一个\verb|parent_type|至\verb|g_type_register_static|和\verb|g_type_register_dynamic|中，然后交给父类来定义。
\section{复制函数}
所有的glib类型（基本和非基本，类化和非类化，可实例化和不可实例化）的最大共同点是都可以通过单一的API来复制或指定它们。

GValue结构被用作所有类型的抽象的容器，它的极度简化的API（定义在gobject/gvalue.h）可以被使用请求\verb|value_table|函数被注册当类型注册中：举个例子，\verb|g_value_copy|复制了GValue的内容至另一个GValue。这与C++指派它的复制操作来修改默认的按位复制C++/C结构是类似的。

下面的代码向你展示了你是如何复制一个64位的整型，同样GObject的实例指针也是这样（代码在/gtype/test.c中）：
\begin{verbatim}
static void test_int (void)
{
  GValue a_value = {0, };
  GValue b_value = {0, };
  guint64 a, b;

  a = 0xdeadbeaf;

  g_value_init (&a_value, G_TYPE_UINT64);
  g_value_set_uint64 (&a_value, a);

  g_value_init (&b_value, G_TYPE_UINT64);
  g_value_copy (&a_value, &b_value);

  b = g_value_get_uint64 (&b_value);

  if (a == b) {
    g_print ("Yay !! 10 lines of code to copy around a uint64.\n");
  } else {
    g_print ("Are you sure this is not a Z80 ?\n");
  }
}

static void test_object (void)
{
  GObject *obj;
  GValue obj_vala = {0, };
  GValue obj_valb = {0, };
  obj = g_object_new (MAMAN_BAR_TYPE, NULL);

  g_value_init (&obj_vala, MAMAN_BAR_TYPE);
  g_value_set_object (&obj_vala, obj);

  g_value_init (&obj_valb, G_TYPE_OBJECT);

  /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference.
     This function thus calls g_object_ref.
     It is interesting to note that the assignment works here because
     MAMAN_BAR_TYPE is a G_TYPE_OBJECT.
   */
  g_value_copy (&obj_vala, &obj_valb);

  g_object_unref (G_OBJECT (obj));
  g_object_unref (G_OBJECT (obj));
}
\end{verbatim}
上面代码的重点是关于复制指令的确切语义，并没有详细的定义复制是如何实现的。复制函数的实现可能是决定请求一新块的内存，并把数据从源复制到目的。或者可能是简单的增加实例的引用数和复制引用至新的GValue。

\verb|value_table|用于详细说明这些定义在gtype.h的函数的使用并彻底地描述在由GObject提供的API文档中，这是为什么我们不追究细节的原因。
\begin{verbatim}
typedef struct _GTypeValueTable         GTypeValueTable;
struct _GTypeValueTable
{
  void     (*value_init)         (GValue       *value);
  void     (*value_free)         (GValue       *value);
  void     (*value_copy)         (const GValue *src_value,
                                  GValue       *dest_value);
  /* varargs functionality (optional) */
  gpointer (*value_peek_pointer) (const GValue *value);
  gchar            *collect_format;
  gchar*   (*collect_value)      (GValue       *value,
                                  guint         n_collect_values,
                                  GTypeCValue  *collect_values,
                                  guint                collect_flags);
  gchar            *lcopy_format;
  gchar*   (*lcopy_value)        (const GValue *value,
                                  guint         n_collect_values,
                                  GTypeCValue  *collect_values,
                                  guint                collect_flags);
};
\end{verbatim}
有趣的是，你同样不需要详细指定一个\verb|value_table|在注册过程中，因为\verb|value_tables|一般从非基本类型的父类中继承，这意味着除非你想写一个基本类型，否则你将不需要提供一个新的\verb|value_table|因为它可以从父类继承\verb|value_table|。

请注意，另外一个注册函数是\verb|g_type_register_dynamic|。我们将不讨论这个函数，因为它与\_static版本非常相似。
\section{GLib的规范}
当用户在头文件中创建新类型时，有一些规范用户需要注意：
\begin{itemize}
	\item 使用\verb|object_method|的形式来定义函数名称：例如在一个bar类中定义一个名为foo的函数，则用\verb|bar_foo|。
	\item 使用前缀来避免与其他工程的命名空间冲突。如果你的库（或应用程序）名为Marman，那么所有的函数名称前缀为\verb|maman_|。举例：\verb|maman_object_method|。
	\item 创建一个宏命为\verb|PREFIX_OBJECT_TYPE|用来返回GType关联的对象类型。比如，Bar这个类在一个以maman前缀的库中，则使用\verb|MANMAN_BAR_TYPE|。另有一个不成文的规定是，定义一个使用全局静态变或一个名为\verb|prefix_object_get_type|的函数来实现这个宏。我们将在后面的章节中讨论这个函数。
	\item 创建一个宏命名为\verb|PREFIX_OBJECT(obj)|来返回一个指向PrefixObject类型的指针。这个宏用于必要时安全地强制转换一个静态类型。运行环境检查时，同样也是安全地执行动态类型。在处理过程中禁用动态类型检查是可行的。例如，我们可以创建\verb|MAMAN_BAR(obj)|来保持先前的例子。
	\item 如果类型是类化的，那么创建一个命令为\verb|PREFIX_OBJECT_CLASS（klass）|的宏。这个宏与前面那个是非常相似的：它以类结构的动态类型检查来进行静态转换，并返回一个指向PrefixObjectClass这个类型的类结构的指针。同样，例子为：\verb|MAMAN_BAR_CLASS|。
	\item 创建一个宏命名为\verb|PREFIX_IS_BAR (obj)|：这个宏用于判断输入的对象实例是否是BAR类型的。
	\item 如果类型是类化的，创建一个名为\verb|PREFIX_IS_OBJECT_CLASS (klass)|的宏，与上面的类似，返回输入的类型指针是否是OBJECT类型。
	\item 如果类型是类化的，创建一个名为\verb|PREFIX_OBJECT_GET_CLASS|，返回一个实例所属的类的类型指针。这个宏因为安全的原因，被静态和动态类型所使用，就像上面的转换宏一样。
\end{itemize}
至于这些宏的实现是非常直观的：一些数量的简单使用的宏由gtype.h提供。针对上面我们兴趣的例子，我们写了下面的代码来声明这些宏：
\begin{verbatim}
#define MAMAN_BAR_TYPE                  (maman_bar_get_type ())
#define MAMAN_BAR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_BAR_TYPE, MamanBar))
#define MAMAN_BAR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_BAR_TYPE, MamanBarClass))
#define MAMAN_IS_BAR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_BAR_TYPE))
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_BAR_TYPE))
#define MAMAN_BAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_BAR_TYPE, MamanBarClass))
\end{verbatim}
下面的代码实现了\verb|maman_bar_get_type|这个函数：
\begin{verbatim}
GType maman_bar_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      /* You fill this structure. */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "MamanBarType",
                                   &info, 0);
  }
  return type;
}
\end{verbatim}
\section{不可实例和不可类化的类型：基础类型}
在类型系统中，许多类型是不可实例化而且没有父类的。大多数这些类型是最基础的基本类型，如gchar，它由\verb|g_value_types_init|注册（在gvaluetypes.c中）。

如果想在类型系统中注册这样一个类型，你仅仅需要用0来填充GTypeInfo结构。
\begin{verbatim}
  GTypeInfo info = {
    0,                                /* class_size */
    NULL,                        /* base_init */
    NULL,                        /* base_destroy */
    NULL,                        /* class_init */
    NULL,                        /* class_destroy */
    NULL,                        /* class_data */
    0,                                /* instance_size */
    0,                                /* n_preallocs */
    NULL,                        /* instance_init */
    NULL,                        /* value_table */
  };
  static const GTypeValueTable value_table = {
    value_init_long0,                /* value_init */
    NULL,                        /* value_free */
    value_copy_long0,                /* value_copy */
    NULL,                        /* value_peek_pointer */
    "i",                        /* collect_format */
    value_collect_int,        /* collect_value */
    "p",                        /* lcopy_format */
    value_lcopy_char,                /* lcopy_value */
  };
  info.value_table = &value_table;
  type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo, 0);
\end{verbatim}

使用不可实例的类型似乎是无用的：定义一个不能实例化的类型有什么好处呢？大多数这种类型与GValue用作一块：一个GValue由一个整型或一个字符串来初始化，再被传递了一个已注册类型的\verb|value_table|。GValue（以基本类型延伸）最有用的时候是在与对象的属性和信号用在一块时。
\section{可实例化的类型：对象}
一个以类来注册，并声明为可实例化的类型常常称作对象。GObject（定义在The GObject base class中）是最有名的一个可实例化的类了，其他相似的类都继承于这个基本类来进行开发，他们都基于下面所述的基本特征。

下面的例子告诉你怎样才可以在类型系统中注册这样一个基本的类。
\begin{verbatim}
typedef struct {
  GObject parent;
  /* instance members */
  int field_a;
} MamanBar;

typedef struct {
  GObjectClass parent;
  /* class members */
  void (*do_action_public_virtual) (MamanBar *self, guint8 i);

  void (*do_action_public_pure_virtual) (MamanBar *self, guint8 i);
} MamanBarClass;

#define MAMAN_BAR_TYPE (maman_bar_get_type ())

GType 
maman_bar_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (MamanBarClass),
      NULL,           /* base_init */
      NULL,           /* base_finalize */
      (GClassInitFunc) foo_class_init,
      NULL,           /* class_finalize */
      NULL,           /* class_data */
      sizeof (MamanBar),
      0,              /* n_preallocs */
      (GInstanceInitFunc) NULL /* instance_init */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "BarType",
                                   &info, 0);
  }
  return type;
}
\end{verbatim}
在调用\verb|maman_bar_get_type|之前，名为BarType的继承于\verb|G_TYPE_OBJECT|的类将在类型系统中被注册。

每个对象必须定义为两个结构：它的类结构和它的实例结构。所有的类结构的第一个成员必须是一个GTypeClass结构。所有的实例结构的第一个成员必须是GTypeInstance结构。下面显示了这些来自gtype.h的C类型的声明：

\begin{verbatim}
struct _GTypeClass
{
  GType g_type;
};
struct _GTypeInstance
{
  GTypeClass *g_class;
};
\end{verbatim}
这些约束使得类型系统可以确保每个对象的实例(由指向该对象的实例结构的指针所标识) 的首字节指向该对象的类结构。

这个关系可以由下面的例子来很好的解释：让我们来看看这个继承于对象A的对象B。

\begin{verbatim}
/* A definitions */
typedef struct {
  GTypeInstance parent;
  int field_a;
  int field_b;
} A;
typedef struct {
  GTypeClass parent_class;
  void (*method_a) (void);
  void (*method_b) (void);
} AClass;

/* B definitions. */
typedef struct {
  A parent;
  int field_c;
  int field_d;
} B;
typedef struct {
  AClass parent_class;
  void (*method_c) (void);
  void (*method_d) (void);
} BClass;
\end{verbatim}
上述标准的C结构定义指示了这个C结构的第一个领域存储着类的结构。This means that the first field of an instance of an object B is A’s first field which in turn is GTypeInstance’s first field which in turn is \verb|g_class|, a pointer to B’s class structure.

多亏了这些简单的条件，所以按下面的方法来就可能取得每个对象实例的类型：
\begin{verbatim}
B *b;
b->parent.parent.g_class->g_type
\end{verbatim}
或者，更快的：
\begin{verbatim}
B *b;
((GTypeInstance*)b)->g_class->g_type
\end{verbatim}
\subsection{初始化和销毁}
实例化这些类型可以用\verb|g_type_create_instance|来完成：
\begin{verbatim}
GTypeInstance* g_type_create_instance (GType          type);
void           g_type_free_instance   (GTypeInstance *instance);
\end{verbatim}

\verb|g_type_create_instance|将查找请求的类型所关联的类型信息结构。然后由用户声明的实例的大小和实例化策略（如果\verb|n_preallocs|设置为一个非零值，类型系统将会把对象的实例结构分配在内存块上，而不将依次分配每个实例）将得到一个缓存来保存对象实例的结构。

如果实例是这个对象第一次创建的，那么类型系统必须创建一个类结构：它为其分配一个缓冲来保存这个对象的类结构并初始化它。它先用父类的类结构覆盖（如果没有父类，它将初始化为零），然后从最顶层的基本对象至最底层的对象调用\verb|base_class_initialization|函数（GBaseInitFunc）。对象的类初始化函数（GClassInitFunc）被调用来完成类结构的初始化。最终，这个类的接口被初始化了（我们将在后面讨论接口初始化）。

一旦类型系统有一个指向初始化的类结构的指针，它设置对象的实例类指针指向对象的类结构并调用实例的初始化函数（GInstanceInitFunc），同样是从顶到底的顺序。

对象的实例的销毁非常简单，通过\verb|g_type_free_instance|即可：实例结构被返回到实例池中，如果这是对象的还有一个而且是最后一个存活的实例，那么这个类即被摧毁。

类的销毁（关于这个销毁的另一概念是GType的终结）的过程与初始化的刚好对称：接口先被销毁。然后，调用类终结函数\verb|class_finalize|（ClassFinalizeFunc）。最终，将\verb|base_class_finalize|（GBaseFinalizeFunc）从底至顶的调用，直到类结构被销毁。

很多读者已经明白了，基本的初始化/终结化过程与C++的构造/析构函数非常相似。实际上细节是非常不同的，千万不要被表现的相似所迷惑。特别是，大多数用户开始认识到GType中并不存在类似于C++的构造器（这实际上是一个方法列表，由对象实例来调用所有有继承关系的方法），它必须建立在由 GType提供的特定的设施里。同样的，GType没有实例销毁机制。这是用户的职责，在现存的GType代码的顶端来实现正确的销毁（这就是 GObject做的事情）。

举个例子，如果从A继承的对象B被实例化了，GType将只调用对象B的\verb|instance_init|回调函数，而C++运行环境将先调用对象A的构造器，接着再是对象B。事实上，C++代码与GType的\verb|base_init|和\verb|class_init|回调是等同的，不过C++常常是不需要这些的，因为它并不能真的在运行时创建类型。

关于实例化和终结化的处理过程可以归纳如下：

\section{不可实例的类型：接口}
GType的接口（Interface）与Java的接口非常类似。它允许描述一个通用的API，使得多个类可以粘合在一起。想像一下，Hi-Fi音响设备中的暂停和播放按钮──这可以被视做一个回放接口。如果你知道你要做什么，你可以用来这个接口来控制你的CD机，MP3或其他使用相同符号的东西。要声明一个接口，你需要注册一个从GTypeInterface继承的不可实例的类型。下面的代码声明了这样的一个接口：

\begin{verbatim}
#define MAMAN_IBAZ_TYPE                (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz))
#define MAMAN_IS_IBAZ(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE))
#define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, MamanIbazInterface))

typedef struct _MamanIbaz MamanIbaz; /* dummy object */
typedef struct _MamanIbazInterface MamanIbazInterface;

struct _MamanIbazInterface {
  GTypeInterface parent;

  void (*do_action) (MamanIbaz *self);
};

GType maman_ibaz_get_type (void);

void maman_ibaz_do_action (MamanIbaz *self);
\end{verbatim}

这里用非常简单的方法来实现\verb|maman_ibaz_do_action|这个接口函数：
\begin{verbatim}
void maman_ibaz_do_action (MamanIbaz *self)
{
  MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
}
\end{verbatim}

\verb|maman_ibaz_get_type|注册了一个从\verb|G_TYPE_INTERFACE|继承的名为MamanIBaz的类型。在继承树中，所有的接口必须是\verb|G_TYPE_INTERFACE|的子类。

一个接口只有一个包含GTypeInterface的结构来定义。接口的结构应该要包含一个函数指针指向这个接口的方法。用类似于\verb|maman_ibaz_do_action|的方法在每个接口方法中定义帮助函数，可以使得我们直接调用接口方法，这是一个良好的风格。

一旦一个接口的类型被注册后，你必须来实现这个接口。其中，命名为\verb|maman_baz_get_type|注册一个名为MamanBaz的由GObject继承来的新的GType，并在接口Interface中实现。
\begin{verbatim}
static void maman_baz_do_action (MamanIbaz *self)
{
  g_print ("Baz implementation of IBaz interface Action.\n");
}


static void
baz_interface_init (gpointer         g_iface,
                    gpointer         iface_data)
{
  MamanIbazInterface *iface = (MamanIbazInterface *)g_iface;
  iface->do_action = maman_baz_do_action;
}

GType 
maman_baz_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (MamanBazInterface),
      NULL,   /* base_init */
      NULL,   /* base_finalize */
      NULL,   /* class_init */
      NULL,   /* class_finalize */
      NULL,   /* class_data */
      sizeof (MamanBaz),
      0,      /* n_preallocs */
      NULL    /* instance_init */
    };
    static const GInterfaceInfo ibaz_info = {
      (GInterfaceInitFunc) baz_interface_init,    /* interface_init */
      NULL,               /* interface_finalize */
      NULL          /* interface_data */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "MamanBazType",
                                   &info, 0);
    g_type_add_interface_static (type,
                                 MAMAN_IBAZ_TYPE,
                                 &ibaz_info);
  }
  return type;
}
\end{verbatim}
\verb|g_type_add_interface_static|记录了在类型系统中如FooInterface来实现的接口（\verb|foo_interface_get_type|返回FooInterface的类型），GInterfaceInfo保存着关于接口实现的信息：
\begin{verbatim}
struct _GInterfaceInfo
{
  GInterfaceInitFunc     interface_init;
  GInterfaceFinalizeFunc interface_finalize;
  gpointer               interface_data;
};
\end{verbatim}

\subsection{接口初始化}
当一个对象的第一次注册一个接口实现时， 它的类结构由下述的方法所初始化。等类结构初始化后，函数\verb|type_class_init_Wm|（实现在gtype.c）会初始化由类关联的每个接口，以\verb|type_iface_vtable_init_Wm|调用每个接口。

首先为接口结构分配内存缓冲，父接口结构先被复制（父接口先被初始化）。如果没有父接口，接口结构将由0初始化。\verb|g_type|和\verb|g_instance_type|将在其后被初始化：\verb|g_type|被设置为最先起源的接口，\verb|g_instance_type|被设置为最先起源的实现这个接口的类。

最终，接口的最顶层的\verb|base_init|函数和实现接口的\verb|interface_init|被调用。了解下面是重要的：如果有一个接口有多个\verb|base_init|和\verb|interface_init|的实现，那么每个实现都被调用一次以初始化。

\verb|base_init|函数保持了一个本地静态变量用来确保这个接口类型只被初始化一次而不管它是否被实现了几次：
\begin{verbatim}
static void
maman_ibaz_base_init (gpointer g_iface)
{
  static gboolean initialized = FALSE;

  if (!initialized) {
    /* create interface signals here. */
    initialized = TRUE;
  }
}
\end{verbatim}
如果你发现接口很烦，确实如此。它确实很烦，但是我也没办法啊。我只有把接口的过程归纳一下了！

\subsection{接口的销毁}

当最后一个实现某接口的实例被销毁以后，这个与类型相关联的接口实现也将由\verb|type_iface_vtable_finalize_Wm|来销毁（gtype.c）

\verb|type_iface_vtable_finalize_Wm|调用了第一个实现的\verb|interface_finalize|函数，接着是接口最底层的\verb|base_finalize|函数。

同样，下面的理解非常重要，如“接口的初始化”中描述的，\verb|interface_finalize|和\verb|base_finalize|都将被调用来确保一个接口的实现被正确的销毁。例如，如果你曾用过其中一个函数，你将需要使用一个静态的整形来保持有关实例实现的接口的数量，这样接口的类才会只被销毁一次（当整型变量为0时）。

上面的处理过程总结如下：

你已经读完了这章，现在你可以忘记它了。请尽可能快地忘记它！
